import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import crypto from 'crypto'
import { getDatabase } from '../database/init'

// JWT配置
const JWT_SECRET: string = process.env.JWT_SECRET || 'aide_jwt_secret_key_change_in_production'
const JWT_EXPIRES_IN: string = process.env.JWT_EXPIRES_IN || '7d'
const REFRESH_TOKEN_EXPIRES_IN: string = '30d'

// 验证码配置
const VERIFICATION_CODE_LENGTH = 6
const VERIFICATION_CODE_EXPIRES_MINUTES = 5
const MAX_VERIFICATION_ATTEMPTS = 3

export interface User {
  id: string
  email?: string
  phone?: string
  username?: string
  avatar_url?: string
  is_verified: boolean
  login_type: 'email' | 'phone' | 'oauth'
  created_at: string
  updated_at: string
  last_login_at?: string
}

export interface AuthResult {
  success: boolean
  user?: User
  token?: string
  refresh_token?: string
  message: string
  error?: string
}

export interface VerificationResult {
  success: boolean
  message: string
  error?: string
  code_id?: string
}

export class AuthService {
  
  // 生成JWT令牌
  static generateTokens(userId: string) {
    const payload = { userId, type: 'access' }
    const refreshPayload = { userId, type: 'refresh' }
    
    const token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } as jwt.SignOptions)
    const refresh_token = jwt.sign(refreshPayload, JWT_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRES_IN } as jwt.SignOptions)
    
    return { token, refresh_token }
  }
  
  // 验证JWT令牌
  static verifyToken(token: string): { userId: string } | null {
    try {
      const decoded = jwt.verify(token, JWT_SECRET) as any
      if (decoded.type === 'access') {
        return { userId: decoded.userId }
      }
      return null
    } catch (error) {
      return null
    }
  }
  
  // 邮箱密码注册
  static async registerWithEmail(email: string, password: string, username?: string): Promise<AuthResult> {
    const client = await getDatabase().connect()
    
    try {
      // 检查邮箱是否已存在
      const existingUser = await client.query(
        'SELECT id FROM users WHERE email = $1',
        [email]
      )
      
      if (existingUser.rows.length > 0) {
        return {
          success: false,
          message: '该邮箱已被注册',
          error: 'EMAIL_EXISTS'
        }
      }
      
      // 密码强度验证
      if (password.length < 6) {
        return {
          success: false,
          message: '密码长度至少6位',
          error: 'WEAK_PASSWORD'
        }
      }
      
      // 加密密码
      const password_hash = await bcrypt.hash(password, 12)
      
      // 创建用户
      const result = await client.query(`
        INSERT INTO users (email, password_hash, username, login_type, is_verified)
        VALUES ($1, $2, $3, 'email', FALSE)
        RETURNING id, email, username, is_verified, login_type, created_at, updated_at
      `, [email, password_hash, username || email.split('@')[0]])
      
      const user = result.rows[0]
      const tokens = this.generateTokens(user.id)
      
      // 记录登录会话
      await this.createSession(user.id, tokens.token, client)
      
      return {
        success: true,
        user: user,
        token: tokens.token,
        refresh_token: tokens.refresh_token,
        message: '注册成功'
      }
      
    } catch (error) {
      console.error('邮箱注册失败:', error)
      return {
        success: false,
        message: '注册失败，请重试',
        error: 'REGISTRATION_FAILED'
      }
    } finally {
      client.release()
    }
  }
  
  // 邮箱密码登录
  static async loginWithEmail(email: string, password: string): Promise<AuthResult> {
    const client = await getDatabase().connect()
    
    try {
      // 查找用户
      const result = await client.query(`
        SELECT id, email, password_hash, username, avatar_url, is_verified, login_type, created_at, updated_at
        FROM users 
        WHERE email = $1 AND login_type = 'email'
      `, [email])
      
      if (result.rows.length === 0) {
        return {
          success: false,
          message: '邮箱或密码错误',
          error: 'INVALID_CREDENTIALS'
        }
      }
      
      const user = result.rows[0]
      
      // 验证密码
      const isValidPassword = await bcrypt.compare(password, user.password_hash)
      if (!isValidPassword) {
        return {
          success: false,
          message: '邮箱或密码错误',
          error: 'INVALID_CREDENTIALS'
        }
      }
      
      // 生成令牌
      const tokens = this.generateTokens(user.id)
      
      // 更新最后登录时间
      await client.query(
        'UPDATE users SET last_login_at = NOW() WHERE id = $1',
        [user.id]
      )
      
      // 记录登录会话
      await this.createSession(user.id, tokens.token, client)
      
      // 移除敏感信息
      delete user.password_hash
      
      return {
        success: true,
        user: user,
        token: tokens.token,
        refresh_token: tokens.refresh_token,
        message: '登录成功'
      }
      
    } catch (error) {
      console.error('邮箱登录失败:', error)
      return {
        success: false,
        message: '登录失败，请重试',
        error: 'LOGIN_FAILED'
      }
    } finally {
      client.release()
    }
  }
  
  // 发送手机验证码
  static async sendPhoneVerificationCode(phone: string, type: 'login' | 'register' = 'login'): Promise<VerificationResult> {
    const client = await getDatabase().connect()
    
    try {
      // 手机号格式验证
      if (!/^1[3-9]\d{9}$/.test(phone)) {
        return {
          success: false,
          message: '手机号格式不正确',
          error: 'INVALID_PHONE'
        }
      }
      
      // 检查是否频繁发送
      const recentCode = await client.query(`
        SELECT id FROM verification_codes 
        WHERE recipient = $1 AND type = $2 AND created_at > NOW() - INTERVAL '1 minute'
        ORDER BY created_at DESC LIMIT 1
      `, [phone, `phone_${type}`])
      
      if (recentCode.rows.length > 0) {
        return {
          success: false,
          message: '请等待1分钟后再发送',
          error: 'TOO_FREQUENT'
        }
      }
      
      // 如果是注册，检查手机号是否已存在
      if (type === 'register') {
        const existingUser = await client.query(
          'SELECT id FROM users WHERE phone = $1',
          [phone]
        )
        
        if (existingUser.rows.length > 0) {
          return {
            success: false,
            message: '该手机号已被注册',
            error: 'PHONE_EXISTS'
          }
        }
      }
      
      // 如果是登录，检查手机号是否存在
      if (type === 'login') {
        const existingUser = await client.query(
          'SELECT id FROM users WHERE phone = $1',
          [phone]
        )
        
        if (existingUser.rows.length === 0) {
          return {
            success: false,
            message: '该手机号未注册，请先注册',
            error: 'PHONE_NOT_EXISTS'
          }
        }
      }
      
      // 生成验证码
      const code = Math.random().toString().slice(-VERIFICATION_CODE_LENGTH).padStart(VERIFICATION_CODE_LENGTH, '0')
      const expires_at = new Date(Date.now() + VERIFICATION_CODE_EXPIRES_MINUTES * 60 * 1000)
      
      // 清理旧的验证码
      await client.query(`
        DELETE FROM verification_codes 
        WHERE recipient = $1 AND type = $2
      `, [phone, `phone_${type}`])
      
      // 保存验证码
      const result = await client.query(`
        INSERT INTO verification_codes (recipient, code, type, expires_at)
        VALUES ($1, $2, $3, $4)
        RETURNING id
      `, [phone, code, `phone_${type}`, expires_at])
      
      const code_id = result.rows[0].id
      
      // TODO: 调用短信服务发送验证码
      // 这里暂时只是模拟，实际需要集成短信服务商
      console.log(`📱 发送验证码到 ${phone}: ${code} (${VERIFICATION_CODE_EXPIRES_MINUTES}分钟内有效)`)
      
      // 开发环境下返回验证码（生产环境删除）
      const response: VerificationResult = {
        success: true,
        message: '验证码发送成功',
        code_id
      }
      
      if (process.env.NODE_ENV === 'development') {
        (response as any).dev_code = code // 开发环境返回验证码
      }
      
      return response
      
    } catch (error) {
      console.error('发送验证码失败:', error)
      return {
        success: false,
        message: '发送失败，请重试',
        error: 'SEND_FAILED'
      }
    } finally {
      client.release()
    }
  }
  
  // 手机验证码登录/注册
  static async loginWithPhone(phone: string, code: string, username?: string): Promise<AuthResult> {
    const client = await getDatabase().connect()
    
    try {
      // 验证验证码
      const codeResult = await client.query(`
        SELECT id, type FROM verification_codes 
        WHERE recipient = $1 AND code = $2 AND expires_at > NOW() AND is_used = FALSE
        ORDER BY created_at DESC LIMIT 1
      `, [phone, code])
      
      if (codeResult.rows.length === 0) {
        return {
          success: false,
          message: '验证码错误或已过期',
          error: 'INVALID_CODE'
        }
      }
      
      const verificationCode = codeResult.rows[0]
      
      // 标记验证码为已使用
      await client.query(
        'UPDATE verification_codes SET is_used = TRUE WHERE id = $1',
        [verificationCode.id]
      )
      
      // 查找或创建用户
      let user
      const existingUser = await client.query(`
        SELECT id, phone, username, avatar_url, is_verified, login_type, created_at, updated_at
        FROM users WHERE phone = $1
      `, [phone])
      
      if (existingUser.rows.length > 0) {
        // 用户已存在，直接登录
        user = existingUser.rows[0]
        
        // 更新最后登录时间
        await client.query(
          'UPDATE users SET last_login_at = NOW() WHERE id = $1',
          [user.id]
        )
      } else {
        // 用户不存在，自动注册
        const result = await client.query(`
          INSERT INTO users (phone, username, login_type, is_verified)
          VALUES ($1, $2, 'phone', TRUE)
          RETURNING id, phone, username, avatar_url, is_verified, login_type, created_at, updated_at
        `, [phone, username || `用户${phone.slice(-4)}`])
        
        user = result.rows[0]
      }
      
      // 生成令牌
      const tokens = this.generateTokens(user.id)
      
      // 记录登录会话
      await this.createSession(user.id, tokens.token, client)
      
      return {
        success: true,
        user: user,
        token: tokens.token,
        refresh_token: tokens.refresh_token,
        message: existingUser.rows.length > 0 ? '登录成功' : '注册并登录成功'
      }
      
    } catch (error) {
      console.error('手机登录失败:', error)
      return {
        success: false,
        message: '登录失败，请重试',
        error: 'LOGIN_FAILED'
      }
    } finally {
      client.release()
    }
  }
  
  // 创建用户会话
  private static async createSession(userId: string, token: string, client: any) {
    const tokenHash = crypto.createHash('sha256').update(token).digest('hex')
    const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天
    
    await client.query(`
      INSERT INTO user_sessions (user_id, token_hash, expires_at)
      VALUES ($1, $2, $3)
    `, [userId, tokenHash, expiresAt])
  }
  
  // 获取用户信息
  static async getUserById(userId: string): Promise<User | null> {
    const client = await getDatabase().connect()
    
    try {
      const result = await client.query(`
        SELECT id, email, phone, username, avatar_url, is_verified, login_type, created_at, updated_at, last_login_at
        FROM users WHERE id = $1
      `, [userId])
      
      return result.rows[0] || null
    } catch (error) {
      console.error('获取用户信息失败:', error)
      return null
    } finally {
      client.release()
    }
  }
  
  // 登出
  static async logout(token: string): Promise<boolean> {
    const client = await getDatabase().connect()
    
    try {
      const tokenHash = crypto.createHash('sha256').update(token).digest('hex')
      
      await client.query(
        'DELETE FROM user_sessions WHERE token_hash = $1',
        [tokenHash]
      )
      
      return true
    } catch (error) {
      console.error('登出失败:', error)
      return false
    } finally {
      client.release()
    }
  }
}
